/*
 *   Licensed to the Apache Software Foundation (ASF) under one
 *   or more contributor license agreements.  See the NOTICE file
 *   distributed with this work for additional information
 *   regarding copyright ownership.  The ASF licenses this file
 *   to you under the Apache License, Version 2.0 (the
 *   "License"); you may not use this file except in compliance
 *   with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing,
 *   software distributed under the License is distributed on an
 *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 *   KIND, either express or implied.  See the License for the
 *   specific language governing permissions and limitations
 *   under the License.
 *
 */

package org.apache.directory.http.client;


import java.util.Iterator;

import org.apache.directory.server.codec.json.JsonBuilder;
import org.apache.directory.server.http.AppConstants;
import org.apache.directory.shared.i18n.I18n;
import org.apache.directory.shared.ldap.cursor.ClosureMonitor;
import org.apache.directory.shared.ldap.cursor.Cursor;
import org.apache.directory.shared.ldap.cursor.InvalidCursorPositionException;
import org.apache.directory.shared.ldap.entry.DefaultEntry;
import org.apache.directory.shared.ldap.message.LdapResult;
import org.apache.directory.shared.ldap.message.LdapResultImpl;
import org.apache.directory.shared.ldap.message.SearchResultDone;
import org.apache.directory.shared.ldap.message.SearchResultDoneImpl;
import org.apache.directory.shared.ldap.message.SearchResultEntry;
import org.apache.directory.shared.ldap.message.SearchResultEntryImpl;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;


/**
 * A cursor to get SearchResponses after setting the underlying cursor's
 * ServerEntry object in SearchResultEnty object
 *
 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
 */
public class JsonEntryToResponseCursor<Response> implements Cursor<Response>
{
    /** a reference to hold the SearchResultDone response */
    private SearchResultDone searchDoneResp;

    private int messageId;

    private DefaultEntry entry;

    private Iterator<JsonElement> results;

    private ClosureMonitor monitor;


    public JsonEntryToResponseCursor()
    {
        results = new JsonArray().iterator();
    }
    
    public JsonEntryToResponseCursor( String jsonSearchResults )
    {
        JsonObject json = new JsonParser().parse( jsonSearchResults ).getAsJsonObject();

        JsonArray resultsArray = json.get( AppConstants.SEARCH_RESULTS_KEY ).getAsJsonArray();
        results = resultsArray.iterator();
        
        searchDoneResp = new SearchResultDoneImpl();
        LdapResult original = JsonBuilder.get().fromJson( json.get( AppConstants.LDAP_RESULT_KEY ), LdapResultImpl.class );
        
        LdapResult userResult = searchDoneResp.getLdapResult();
        userResult.setErrorMessage( original.getErrorMessage() );
        userResult.setMatchedDn( original.getMatchedDn() );
        userResult.setReferral( original.getReferral() );
        userResult.setResultCode( original.getResultCode() );
    }


    public boolean available()
    {
        return ( entry != null );
    }


    public void close() throws Exception
    {
        results = null;
        entry = null;
    }


    public void close( Exception e ) throws Exception
    {
        close();
    }


    public Response get() throws Exception
    {
        if( !available() )
        {
            throw new InvalidCursorPositionException( "no entry present at this current position" );
        }
        
        SearchResultEntry se = new SearchResultEntryImpl( messageId );
        se.setEntry( entry );

        return ( Response ) se;
    }


    public boolean next() throws Exception
    {
        boolean next = results.hasNext();
        if ( next )
        {
            JsonElement json = results.next();
            entry = JsonBuilder.get().fromJson( json, DefaultEntry.class );
        }

        return next;
    }


    /**
     * gives the SearchResultDone message received at the end of search results
     *
     * @return the SearchResultDone message, null if the search operation fails for any reason
     */
    public SearchResultDone getSearchDone()
    {
        return searchDoneResp;
    }


    public boolean isClosed() throws Exception
    {
        return ( ( results == null ) || results.hasNext() );
    }


    public boolean isElementReused()
    {
        return true;
    }


    public Iterator<Response> iterator()
    {
        throw new UnsupportedOperationException();
    }


    public void after( Response resp ) throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public void afterLast() throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public boolean first() throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public void before( Response resp ) throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public void beforeFirst() throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public boolean last() throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public boolean previous() throws Exception
    {
        throw new UnsupportedOperationException();
    }


    public void setClosureMonitor( ClosureMonitor monitor )
    {
        this.monitor = monitor;
    }


    /**
     * {@inheritDoc}
     */
    public boolean isAfterLast() throws Exception
    {
        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
            .concat( "." ).concat( "isAfterLast()" ) ) );
    }


    /**
     * {@inheritDoc}
     */
    public boolean isBeforeFirst() throws Exception
    {
        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
            .concat( "." ).concat( "isBeforeFirst()" ) ) );
    }


    /**
     * {@inheritDoc}
     */
    public boolean isFirst() throws Exception
    {
        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
            .concat( "." ).concat( "isFirst()" ) ) );
    }


    /**
     * {@inheritDoc}
     */
    public boolean isLast() throws Exception
    {
        throw new UnsupportedOperationException( I18n.err( I18n.ERR_02014_UNSUPPORTED_OPERATION, getClass().getName()
            .concat( "." ).concat( "isLast()" ) ) );
    }
}
